#pragma once

#include "llvm/ADT/StringRef.h"
#include "llvm/Support/raw_ostream.h"
#include "type.h"
#include "diag_engine.h"

// char stream -> token

enum class TokenType
{
    number,     // [0-9]+
    indentifier,// 变量
    kw_int,     // int
    plus,       // +
    minus,      // -
    star,       // *
    slash,      // /
    equal,      // =
    l_parent,   // (
    r_parent,   // )
    semi,       // ;
    comma,      // ,
    eof         // end of file
};

class Token
{
public:
    Token()
    {
        row = col = -1;
        value = -1;
    }
    void Dump();
    static llvm::StringRef GetSpellingText(TokenType tokenType);
public:
    int row, col;
    TokenType tokenType; // token 的种类
    int value;
    int length;
    const char *ptr;
    CType *type;
};

class Lexer
{
private:
    DiagEngine &diagEngine;
    llvm::SourceMgr& mgr;
public:
    Lexer(DiagEngine &diagEngine, llvm::SourceMgr &mgr): diagEngine(diagEngine), mgr(mgr)
    {
        unsigned id = mgr.getMainFileID();
        llvm::StringRef buf = mgr.getMemoryBuffer(id)->getBuffer();
        BufPtr = buf.begin();
        LineHeadPtr = buf.begin();
        BufEnd = buf.end();
        row = 1;
    }
    void NextToken(Token& token);

    void SaveState();
    void RestoreState();

    DiagEngine &GetDiagEngine() const
    {
        return diagEngine;
    }
private:
    struct State
    {
        const char * BufPtr;
        const char * LineHeadPtr;
        const char * BufEnd;
        int row;
    };
private:
    const char * BufPtr;
    const char * LineHeadPtr;
    const char * BufEnd;
    int row;

    State state;
};